package com.xayy.health.mgt.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.Method;
import cn.kawins.base.result.CheckResult;
import cn.kawins.base.utils.CollUtil;
import cn.kawins.base.utils.HttpUtil;
import cn.kawins.base.utils.StringUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.xayy.health.core.config.param.AlgorithmParam;
import com.xayy.health.core.constant.TableNameConstant;
import com.xayy.health.core.enums.ModelTrainStatusEnum;
import com.xayy.health.core.enums.ModuleEnum;
import com.xayy.health.core.enums.SystemModelTypeEnum;
import com.xayy.health.core.exception.HealthException;
import com.xayy.health.core.utils.ConvertUtils;
import com.xayy.health.mgt.mapper.CalculateDataMapper;
import com.xayy.health.mgt.mapper.FaultInfoMapper;
import com.xayy.health.mgt.mapper.HealthAlgorithmManageMapper;
import com.xayy.health.mgt.mapper.SelectTelemetryDataSourceMapper;
import com.xayy.health.mgt.model.*;
import com.xayy.health.mgt.model.dto.TelemetryDto;
import com.xayy.health.mgt.model.vo.PredictDataVo;
import com.xayy.health.mgt.model.vo.ResultDataVo;
import com.xayy.health.mgt.model.vo.TaskResultVo;
import com.xayy.health.mgt.service.*;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import tk.mybatis.mapper.entity.Example;

import java.math.BigDecimal;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

/**
 * 趋势预测
 * @author zhangxa
 */
@Service
@Slf4j
@SuppressWarnings(value = "all")
public class CalculateServiceImpl   implements CalculateService {

    @Autowired
    private AlgorithmParam algorithmParam;
    @Autowired
    private ModelTrainRecordService modelTrainRecordService;
    @Autowired
    private TaskChildInfoService taskChildInfoService;
    @Autowired
    private  TaskInfoService taskInfoService;
    @Autowired
    private FaultInfoMapper faultInfoMapper;
    @Autowired
    private DataFeatureService telemetryDataService;
    @Autowired
    private ModelTrainAccuracyService modelTrainAccuracyService;
    @Autowired
    private DiagnoseService diagnoseService;
    @Autowired
    private ModelAlgorithmInfoService modelAlgorithmInfoService;

    @Autowired
    private SelectTelemetryDataSourceMapper selectTelemetryDataSourceMapper;

    @Autowired
    private FaultReportService faultReportService;

    @Autowired
    private HealthAlgorithmManageMapper healthAlgorithmManageMapper;

    @Autowired
    private CalculateDataMapper calculateDataMapper;


    /**
     * 模型训练
     *
     * @param modelTrain
     * @return CheckResult<Object>
     * @Param recordId 记录id
     */
    // @Async
    @Override
    public CheckResult<Object> modelTrial(CalculateModelTrain modelTrain, Long recordId) throws UnknownHostException {
        List<AlgorithmParams> algorithmParamList = modelTrain.getAlgorithmParamList();
        if (CollUtil.isEmpty(algorithmParamList) || algorithmParamList.size() != 9)
            return CheckResult.fail("模型参数不能不空");
        List<ModelAlgorithmInfo> modelAlgorithmInfos = this.assembleAlgorithmParamList(modelTrain, recordId, algorithmParamList);
        //旧模型设置模型名称
        if(StrUtil.isNotEmpty(modelTrain.getOldModelName())){
            ModelTrainRecord modelTrainRecord = modelTrainRecordService.selectOne(ModelTrainRecord.builder().id(modelTrain.getOldModelName()).build());
            modelTrain.setModelName(modelTrainRecord.getModelName());
        }
        //判断遥测数据中是否含有空值
        String[] paramCodes =new String[]{modelTrain.getParamCode()};
        TelemetryDto telemetryDto = new TelemetryDto().setSatelliteCode(modelTrain.getSatelliteCode()).setStartTime(modelTrain.getStartTime()).setEndTime(modelTrain.getEndTime()).setParamCodes(paramCodes);
        Map<String, List<TelemetryData>> listMap = diagnoseService.selectTelemetryData(telemetryDto);
        //判断是否存在空值
        for (Map.Entry<String, List<TelemetryData>> map : listMap.entrySet()) {
            List<TelemetryData> list = map.getValue();
            if (!CollectionUtils.isEmpty(list)) {
                for (TelemetryData data : list) {
                    if (StringUtils.isEmpty(data.getValue())) {
                        throw new HealthException("参数 " + map.getKey() + " 存在空值.......");
                    }
                }
            }
        }
        /**查询算法信息*/
        HealthAlgorithmManage algorithm = healthAlgorithmManageMapper.selectAlgorithmByName(modelTrain.getAlgorithmName());
        HttpResponse postResponse;
        try {
            postResponse = HttpUtil.createRequest(Method.POST, algorithm.getTrialAddr()).body(JSON.toJSONString(modelTrain)).execute();
        } catch (Exception e) {
            faultReportService.faultReport(ModuleEnum.SHZD.getCode(), ModuleEnum.SHZD.getMsg(),"调用接口失败","调用接口失败");
            return CheckResult.fail("调用接口失败：" + e.getMessage());
        }
        if (postResponse.getStatus() != 200) {
            try {
                // 修改训练记录状态
                ModelTrainRecord modelTrainRecord = ModelTrainRecord.builder().id(recordId.toString())
                        .status(ModelTrainStatusEnum.ABNORMAL.getCode()).build();
                modelTrainRecordService.updateByIdSelective(modelTrainRecord);
                Map map = JSONObject.parseObject(postResponse.body(), Map.class);
                if (StrUtil.isEmpty(modelTrain.getOldModelName()))
                    modelTrainRecordService.delete(ModelTrainRecord.builder().modelName(modelTrain.getModelName()).build());
                log.error("调用模型训练算法结果异常");
                return CheckResult.fail(map.get("msg").toString());
            } catch (Exception e) {
                faultReportService.faultReport(ModuleEnum.SHZD.getCode(), ModuleEnum.SHZD.getMsg(),"模型训练数据出错","调用算法失败");
                return CheckResult.fail("调用算法失败，http状态码：" + postResponse.getStatus());
            }
        }
        JSONObject result = JSON.parseObject(postResponse.body());
        if (!result.getInteger("code").equals(200)) {
            modelTrainRecordService.updateByIdSelective(ModelTrainRecord.builder().id(recordId.toString()).status(ModelTrainStatusEnum.ABNORMAL.getCode()).build());
            return CheckResult.fail(result.getString("msg"));
        }
        // 修改训练记录状态
        Map<String, Object> data = result.getObject("data", Map.class);
        // BigDecimal acc = (BigDecimal) data.get("acc");
        BigDecimal acc = new BigDecimal(1);
        Object offset = data.get("offset");
        Integer status = (Integer) data.get("status");
        List<Map<String, String>> test_model = (List<Map<String, String>>) data.get("test_model");
        // 旧模型操作
        if (StrUtil.isNotEmpty(modelTrain.getOldModelName())) {
            ModelTrainRecord trainRecord = BeanUtil.copyProperties(modelTrain, ModelTrainRecord.class);
            ModelTrainRecord oldModelTrainRecord = modelTrainRecordService.selectById(modelTrain.getOldModelName());
            trainRecord.setModelName(oldModelTrainRecord.getModelName()).setId(modelTrain.getOldModelName())
                    .setOffset(offset.toString()).setStatus(ModelTrainStatusEnum.DONE.getCode())
                    .setAccuracy(acc.toString());
            modelTrainRecordService.updateByIdSelective(trainRecord);
            modelTrainAccuracyService
                    .delete(ModelTrainAccuracy.builder().modelTrainRecordId(oldModelTrainRecord.getId()).build());
            // 插入修改后的模型数据
            updateModelTrainData(test_model, modelTrain, oldModelTrainRecord.getId(), null);
            updateAlgorithmInfo(true, oldModelTrainRecord.getId(), modelAlgorithmInfos);
        } else {
            ModelTrainRecord modelTrainRecord =
                    ModelTrainRecord.builder().id(recordId.toString()).offset(offset.toString())
                            .status(ModelTrainStatusEnum.DONE.getCode()).accuracy(acc.toString()).build();
            modelTrainRecordService.updateByIdSelective(modelTrainRecord);
            updateAlgorithmInfo(false, recordId.toString(), modelAlgorithmInfos);
            if (CollUtil.isNotEmpty(test_model))
                updateModelTrainData(test_model, modelTrain, null, recordId);
        }
        List<TelemetryData> list = listMap.get(modelTrain.getParamCode());
        log.info("训练完数据格式化为.....list={}",list.get(0));
        if(!CollectionUtils.isEmpty(list)){
            String tableName = TableNameConstant.MODEL_TRAIN_TELEMETRY + recordId;
            selectTelemetryDataSourceMapper.createTaskTable(tableName);
            selectTelemetryDataSourceMapper.deleteTelemetryData(tableName);
            selectTelemetryDataSourceMapper.insertTelemetryListData(tableName, list);
        }
        HashMap<String, Object> testModel = new HashMap<>();
//        if(!CollectionUtils.isEmpty(test_model)){
//            test_model=DiagnoseServiceImpl.addDataToListForTrain(test_model);
//        }
        testModel.put("testModel", test_model);
            return CheckResult.success(testModel);
    }

    /**
     * 修改模型数据
     *
     * @param test_model
     * @param modelTrain
     * @param oldmodelTrainId 判断是否是旧模型
     */
    public void updateModelTrainData(List<Map<String, String>> test_model, CalculateModelTrain modelTrain,
                                     String oldmodelTrainId, Long recordId) {
        ArrayList<ModelTrainAccuracy> telemetryList = new ArrayList<>();
        for (Map<String, String> model : test_model) {
            String time = model.get("time");
            String value = Convert.toStr(model.get("value"));
            ModelTrainAccuracy modelTrainAccuracy = ModelTrainAccuracy.builder().time(time).value(value).valueType("1")
                    .sateCode(modelTrain.getSatelliteCode()).paramCode(modelTrain.getParamCode()).build();
            if (StringUtil.isEmpty(oldmodelTrainId)) {
                modelTrainAccuracy.setModelTrainRecordId(recordId.toString());
            } else {
                modelTrainAccuracy.setModelTrainRecordId(oldmodelTrainId);
            }
            telemetryList.add(modelTrainAccuracy);
        }
        modelTrainAccuracyService.insertList(telemetryList);
    }

    /**
     * 更新算法信息
     *
     * @param isUpdate            是否是旧模型
     * @param modelId             模型id
     * @param modelAlgorithmInfos 模型信息
     */
    private void updateAlgorithmInfo(Boolean isUpdate, String modelId, List<ModelAlgorithmInfo> modelAlgorithmInfos) {
        if (Boolean.TRUE.equals(isUpdate)) {
            modelAlgorithmInfoService.delete(ModelAlgorithmInfo.builder().modelId(modelId).build());
        }
        modelAlgorithmInfoService.insertList(modelAlgorithmInfos);
    }

    /**
     * 调用模型
     *
     * @param modelTrain
     */
    @Override
    public CheckResult<?> startModel(CalculateModelTrain modelTrain) {
        return calculate(modelTrain);
    }


    /**
     * 异步线程池执行任务
     *
     * @param taskInfo 任务信息
     */
    @Override
    public void asyncExcuteTask(TaskInfo taskInfo) throws UnknownHostException {
        /*查询遥测*/
        TelemetryDto telemetryDto = new TelemetryDto();
        telemetryDto.setSatelliteCode(taskInfo.getSatelliteCode());
        telemetryDto.setParamCodes((new String[]{taskInfo.getParams()}));
        telemetryDto.setStartTime(taskInfo.getStartTime());
        telemetryDto.setEndTime(taskInfo.getEndTime());
        /*1 ：预处理平滑后的遥测数据 ，其他：原始遥测数据*/
        Map<String, List<TelemetryData>> taskPlanTelemetry = new HashMap<>(8);
        if(taskInfo.getOriginalDataSources() != null && 1 == taskInfo.getOriginalDataSources()){
            taskPlanTelemetry = diagnoseService.selectPrePhData(telemetryDto);
        }else{
            taskPlanTelemetry = diagnoseService.selectTelemetryData(telemetryDto);
        }
        /*查询遥测是否有空值*/
        boolean isRun = checkTelDateIsEmpty(taskInfo,taskPlanTelemetry);
        /*isRun 为false则不继续执行*/
        if(!isRun){
            return;
        }
        CalculateModelTrain modelTrain = CalculateModelTrain.builder()
                .satelliteMid("")
                .satelliteCode(taskInfo.getSatelliteCode())
                .startTime(taskInfo.getStartTime())
                .endTime(taskInfo.getEndTime())
                .modelName(taskInfo.getModelName())
                .paramCode(taskInfo.getParams())
                .paramCodes(CollUtil.newArrayList(taskInfo.getParams()))
                .predNumber(taskInfo.getPredNumber())
                .timeSpan(taskInfo.getTimeSpan())
                .build();
        String url = algorithmParam.cnnPredictUrl;
        try {
            HttpResponse postResponse = HttpUtil.createRequest(Method.POST, url).body(JSON.toJSONString(modelTrain)).execute();
            if (postResponse.getStatus() != 200) {
                log.error("调用算法失败，http状态码：" + postResponse.getStatus());
                return;
            }
            JSONObject result = JSON.parseObject(postResponse.body());
            if (!result.getInteger("code").equals(200)) {
                log.error("算法业务错误：" + result.getString("msg"));
                return;
            }
            Map<String, Object> data = result.getObject("data", Map.class);
            Object error = data.get("result");
            List<Map<String, Object>> list = JSON.parseObject(String.valueOf(error), List.class);
            List<CalculateData> calculateDataList = new ArrayList<>(CollUtil.isNotEmpty(list) ? list.size() : 0);
            list.forEach(x -> {
                CalculateData calculateData = new CalculateData();
                calculateData.setTaskId(taskInfo.getId());
                calculateData.setSateCode(taskInfo.getSatelliteCode());
                calculateData.setParamCode(taskInfo.getParams());
                calculateData.setTime(x.get("time").toString());
                calculateData.setValue(Double.parseDouble(x.get("value").toString()));
                calculateDataList.add(calculateData);
            });

            // 插入clickhouse数据
            faultInfoMapper.insertCalculateDataList(calculateDataList);
            /*插入所用遥测数据*/
            String tableName = TableNameConstant.RUN_TASK_TELEMETRY + taskInfo.getId();
            selectTelemetryDataSourceMapper.createTaskTable(tableName);
            selectTelemetryDataSourceMapper.deleteTelemetryData(tableName);
            taskPlanTelemetry.forEach((k,v) ->{
                selectTelemetryDataSourceMapper.insertTelemetryListData(tableName,v);
            });
        } catch (Exception e) {
            log.error("任务:{} 执行失败! 异常信息:{}", taskInfo.getName(), ExceptionUtil.getMessage(e));
            faultReportService.faultReport(ModuleEnum.SHZD.getCode(), ModuleEnum.SHZD.getMsg(),"任务执行失败","任务执行失败");
            e.printStackTrace();
        }
    }

    /**
     *  判断遥测是否有空值
     * @param taskInfo 任务信息
     * @param telDataList 遥测数据
     * @param taskChildInfo 子任务信息
     * @return boolean
     */
    private boolean checkTelDateIsEmpty(TaskInfo taskInfo, Map<String, List<TelemetryData>> telDataList) {
        /*定义返回值*/
        AtomicBoolean isContinue = new AtomicBoolean(true);
        /*判断是选择的原始数据还是预处理数据*/
        if(taskInfo.getOriginalDataSources() != null && 1 == taskInfo.getOriginalDataSources()){
            /* 如果是选择数据处理后的数据
             * a.如果此时间段数据已经处理，则看下是否存在空值，有空值则停止该任务的进行
             * b.如果数据处理此参数还没处理此时间段则该任务停上一个所选该参数数据处理时任务的周期，周期过后，若还没数据，则运行下一个子任务
             */
            if(CollUtil.isEmpty(telDataList)){
                /*如果预处理数据为空，并且已经等待一个周期则停止当前任务*/
                if(1 != taskInfo.getPauseEndTimeIsExecute()){
                    isContinue.set(false);
                }else{
                    /*如果预处理数据为空，并且没有等待一个周期则等下个周期在运行*/
                    isContinue.set(false);
                    /*将TaskInfo 运行时间向前推一个周期*/
                    Date runTime = DateUtil.offsetMinute(taskInfo.getLongRunningTime(), -(int) (Double.parseDouble(taskInfo.getCycle()) * 60));
                    taskInfo.setLongRunningTime(runTime);
                    /*修改任务暂停到何时字段，下阶段开始运行,下阶段开始任务执行在 ScheduledTask类中checkTaskIsRun()方法定时任务检测是否到点，到点则开始执行任务 */
                    Date nextRuntime = DateUtil.offsetMinute(new Date(), (int) (Double.parseDouble(taskInfo.getCycle()) * 60));
                    taskInfo.setPauseEndTime(nextRuntime);
                    taskInfo.setPauseEndTimeIsExecute(0);
                    /*修改任务状态为停止*/
                    taskInfo.setStatus(0);
                    /*修改任务运行时间*/
                    taskInfoService.updateByIdSelective(taskInfo);
                }
            }else{
                telDataList.forEach((k, v) -> {
                    if(CollUtil.isNotEmpty(v)){
                        long count = v.stream().filter(f -> StringUtil.isBlank(f.getValue())).count();
                        if(count > 0){
                            /*如果预处理数据出现空值数据则停止当前任务*/
                            isContinue.set(false);
                        }
                    }
                });
            }
        }else{
            /*如果是原始数据则需要检查是否有空值，有的话停止当前任务
             */
            telDataList.forEach((k, v) -> {
                if(CollUtil.isNotEmpty(v)){
                    long count = v.stream().filter(f -> StringUtil.isBlank(f.getValue())).count();
                    if(count > 0){
                        /*如果遥测出现空值数据则停止当前任务*/
                        isContinue.set(false);
                    }
                }
            });
        }
        return isContinue.get();
    }


    /**
     * 根据子任务id获取任务预测点集合
     *
     * @param predictDataVo 任务id
     * @return 结果日志
     */
    @Override
    public CheckResult<Object> getTaskTrendDataList(PredictDataVo predictDataVo) throws UnknownHostException {
        List<String> xAxi = new LinkedList<>();
        List<String> finxAxi = new ArrayList<>();
        HashMap<String, Object> map = new HashMap<>();
        List<TaskResultVo> changeMap =new ArrayList<>();
        List<TelemetryData> telemetryData =new ArrayList<>();
        List<TelemetryData> realTimetelemetryData =new ArrayList<>();
        TelemetryDto convert = Convert.convert(TelemetryDto.class, predictDataVo);
        Map<String, List<TelemetryData>> listMap = diagnoseService.selectUsedTelemetryData(TableNameConstant.RUN_TASK_TELEMETRY + predictDataVo.getTaskId(), convert);
        /*之前查询的遥测*/
//        Map<String, List<TelemetryData>> listMap = diagnoseService.selectTelemetryData(convert);
        if (MapUtil.isNotEmpty(listMap)) {
            telemetryData = listMap.get(predictDataVo.getParamCode());
            if (CollUtil.isNotEmpty(telemetryData)) {
                try {
                    //telemetryData = addDataToListForTrend(telemetryData);
                    DateTime parseStartTime = DateUtil.parse(telemetryData.get(telemetryData.size() - 1).getTime(), "yyyy-MM-dd HH:mm:ss");
                    predictDataVo.setStartTime(parseStartTime);
                    //获取当前时间的趋势预测数据
                    TaskInfo taskInfo= taskInfoService.selectOne(TaskInfo.builder().id(predictDataVo.getTaskId()).build());
                    //添加告警门限
                    map.put("threshold",taskInfo.getThreshold());
                    DateTime trendEndTime =DateUtil.offsetSecond(parseStartTime,taskInfo.getTimeSpan()*taskInfo.getPredNumber());
                    predictDataVo.setTrendEndTime(trendEndTime);
                    List<TaskResultVo> taskTrendDataList = faultInfoMapper.getTaskTrendDataList(predictDataVo);
                    realTimetelemetryData = faultInfoMapper.getRealTimeDataList(predictDataVo);
                    //Long  interruptTime=Long.parseLong(taskInfo.getStep())*60*1000/2;
                    if (CollUtil.isNotEmpty(taskTrendDataList)) {
                        taskTrendDataList = taskTrendDataList.stream().distinct().collect(Collectors.toList());
                        taskTrendDataList.sort(Comparator.comparing(y -> DateUtil.parse(y.getTime(), "yyyy-MM-dd HH:mm:ss.SSS").getTime()));

                        //补全空缺值
                        //taskTrendDataList = addDataToList(taskTrendDataList);
                        taskTrendDataList.sort(Comparator.comparing(y -> DateUtil.parse(y.getTime(), "yyyy-MM-dd HH:mm:ss.SSS").getTime()));
                    }
                    telemetryData.stream().forEach(item -> xAxi.add(item.getTime()));
                    if (CollUtil.isNotEmpty(taskTrendDataList)) {
                        taskTrendDataList.stream().forEach(x -> xAxi.add(x.getTime()));
                    }

                    xAxi.sort(Comparator.comparing(x -> DateUtil.parse(x, "yyyy-MM-dd HH:mm:ss.SSS").getTime()));
                    finxAxi = xAxi.stream().distinct().collect(Collectors.toList());
                    changeMap = addNullValue(finxAxi, taskTrendDataList);
                    telemetryData=addNullValueToTelemetry(finxAxi,telemetryData);
                    realTimetelemetryData = addNullValueToTelemetry(finxAxi,realTimetelemetryData);
                } catch (Exception e) {
                    log.error("请检查遥测数据格式是否正确", e);
                    faultReportService.faultReport(ModuleEnum.SHZD.getCode(), ModuleEnum.SHZD.getMsg(),"测数据格式正确性","检查遥测数据格式是否正确");
                    throw new HealthException("请检查遥测数据格式是否正确");
                }

            }
            map.put("xAis", finxAxi);
            map.put("taskTrendDataList", changeMap);
            map.put("telemetryDataList", telemetryData);
            map.put("realTimeDataList", realTimetelemetryData);
            return CheckResult.success(map);
        }

        return CheckResult.success();

    }

    /**
     * 查询结果数据
     * @param resultDataVo
     * @return 结果日志
     */
    @Override
    public CheckResult<Object> getResultDataList(ResultDataVo resultDataVo) throws UnknownHostException {
        List<CalculateData> dataList = calculateDataMapper.selectResultData(resultDataVo);
        if (null != dataList && dataList.size()>0 )
            return CheckResult.success(dataList);
        else
            return CheckResult.fail("未查询到数据");
    }

    @Override
    public CheckResult<Object> online(TelemetryDto telemetryDto) {
        List<TaskInfo> infoList = taskInfoService.select(TaskInfo.builder().satelliteCode(telemetryDto.getSatelliteCode()).name(telemetryDto.getName()).type(SystemModelTypeEnum.TREND_FORECASTING.getSystemModelTypeCode()).build());
        if (infoList.size() >= 1) {
            return CheckResult.fail("任务名称与任务列表中重复,请修改任务名称");
        }
        /*校验如果选择了处理后的数据需要判断时间和间隔
         * 1.检测开始时间不能早预处理时间
         * 2.轮询周期需要大于预处理周期
         */
        if(telemetryDto.getOriginalDataSources() == 1){
            String msg = checkCycleAndTime(telemetryDto);
            if(msg != null){
                return CheckResult.fail(msg);
            }
        }
        // 新增任务列表
        TaskInfo taskInfo = Convert.convert(TaskInfo.class, telemetryDto);
        taskInfo.setParams(telemetryDto.getParamCode());
        taskInfo.setAlgorithmName(telemetryDto.getAlgorithmName());
        taskInfo.setParamCodeName(telemetryDto.getParamCodeName());
        taskInfo.setName(telemetryDto.getSatelliteCode() + "_" + DateUtil.format(telemetryDto.getStartTime(), "yyyyMMddHHmmss"));
        taskInfo.setEndTime(taskInfo.getStartTime());
        taskInfo.setStatus(1);
        taskInfo.setName(telemetryDto.getName());
        taskInfo.setCycle(telemetryDto.getCycle());
        taskInfo.setStep("10");
        // 记录任务类型
        taskInfo.setType(3);
        taskInfoService.insert(taskInfo);
        return CheckResult.success();
    }

    private String checkCycleAndTime(TelemetryDto telemetryDto) {
        /*构建任务查询条件*/
        Example example = new Example(TaskInfo.class);
        Example.Criteria criteria = example.createCriteria();
        example.orderBy("startTime").desc();
        criteria.andEqualTo("satelliteCode",telemetryDto.getSatelliteCode());
        criteria.andLike("params",telemetryDto.getParamCode());
        criteria.andLike("type","1");
        List<TaskInfo> taskInfos = taskInfoService.selectByExample(example);
        if(CollUtil.isNotEmpty(taskInfos)){
            TaskInfo taskInfo = taskInfos.get(0);
            /*如果事后诊断的开始时间在预处理之前，则给出提示*/
            if(telemetryDto.getStartTime().before(taskInfo.getStartTime())){
                return "开始时间不能早预处理时间【"+taskInfo.getStartTime()+"】";
            }
            /*如果周期小于预处理周期则给出提示*/
            /*趋势预测周期为分钟，需要数据处理的周期(小时)乘以60*/
            if(Integer.parseInt(taskInfo.getCycle())*60 > Integer.parseInt(telemetryDto.getCycle())){
                return "轮询周期不能小于预处理周期【"+taskInfo.getCycle()+"小时】";
            }
        }
        return null;
    }

    /**
     * 补充缺失数据
     * @param taskTrendDataList 待补充集合
     * @return 补充完的集合
     */
    private List<TaskResultVo> addDataToTrendList(List<TaskResultVo> taskTrendDataList,Long interruptTime) {
        List<TaskResultVo> resList=new ArrayList<>();
        if (CollUtil.isNotEmpty(taskTrendDataList)) {
            if(taskTrendDataList.size()>1){
                for(int i=0;i<taskTrendDataList.size()-1;i++){
                    TaskResultVo dto=taskTrendDataList.get(i);
                    TaskResultVo dto2=taskTrendDataList.get(i+1);
                    String time1 = dto.getTime();
                    String time2 = dto2.getTime();
                    time1= ConvertUtils.formatTime(time1);
                    time2=ConvertUtils.formatTime(time2);
                    DateTimeFormatter formatter= DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
                    LocalDateTime timeFormatter1 = LocalDateTime.parse(time1, formatter);
                    LocalDateTime timeFormatter2 = LocalDateTime.parse(time2, formatter);
                    LocalDateTime timeFormatter3=timeFormatter1.plus(interruptTime, ChronoUnit.MILLIS);
                    dto.setTime(time1);
                    resList.add(dto);
                    if(timeFormatter2.isAfter(timeFormatter3)){
                        String startLocalDate = timeFormatter3.toLocalDate() + " " + timeFormatter3.toLocalTime();
                        if(16==startLocalDate.length()){
                            startLocalDate=startLocalDate+":00";
                        }
                        if(!startLocalDate.contains(".")){
                            startLocalDate=startLocalDate+".000";
                        }
                        TaskResultVo res=new TaskResultVo();
                        res.setTime(startLocalDate);
                        resList.add(res);
                    }
                }
                TaskResultVo taskResultVo = taskTrendDataList.get(taskTrendDataList.size() - 1);
                taskResultVo.setTime(ConvertUtils.formatTime(taskResultVo.getTime()));
                resList.add(taskResultVo);
            }else {
                TaskResultVo taskResultVo = taskTrendDataList.get(0);
                taskResultVo.setTime(ConvertUtils.formatTime(taskResultVo.getTime()));
                resList.add(taskResultVo);
            }

        }
        return resList;
    }


    /**
     * 补充数据
     *
     * @param xAxis 横坐标
     * @param list  需要补充的数据
     * @return 补充后结果
     */
    public   static List<TelemetryData> addNullValueToTelemetry(List<String> xAxis, List<TelemetryData> list) {
        List<TelemetryData> finalList = new ArrayList<>();
        if (null != list) {
            Map<Object, TelemetryData> map = new HashMap<>();
            for (TelemetryData vo : list) {
                map.put(vo.getTime(), vo);
            }
            for (String xa : xAxis) {
                if (map.containsKey(xa)) {
                    finalList.add(map.get(xa));
                } else {
                    TelemetryData vo=new TelemetryData();
                    vo.setTime(xa);
                    vo.setValue(null);
                    finalList.add(vo);
                }

            }

        }

        return finalList;
    }


//    /**
//     * 补充缺失数据
//     * @param taskTrendDataList 待补充集合
//     * @return 补充完的集合
//     */
//    private List<TelemetryData> addDataToListForTrend(List<TelemetryData> taskTrendDataList) {
//        List<TelemetryData> resList=new ArrayList<>();
//        if (CollUtil.isNotEmpty(taskTrendDataList)) {
//            if(taskTrendDataList.size()>1){
//                for(int i=0;i<taskTrendDataList.size()-1;i++){
//                    TelemetryData dto=taskTrendDataList.get(i);
//                    TelemetryData dto2=taskTrendDataList.get(i+1);
//                    String time1 = dto.getTime();
//                    String time2 = dto2.getTime();
//                    time1= ConvertUtils.formatTime(time1);
//                    time2=ConvertUtils.formatTime(time2);
//                    DateTimeFormatter formatter= DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
//                    LocalDateTime timeFormatter1 = LocalDateTime.parse(time1, formatter);
//                    LocalDateTime timeFormatter2 = LocalDateTime.parse(time2, formatter);
//                    LocalDateTime timeFormatter3=timeFormatter1.plus(DiagnoseServiceImpl.AMOUNT_TO_ADD, ChronoUnit.MILLIS);
//                    dto.setTime(time1);
//                    resList.add(dto);
//                    if(timeFormatter2.isAfter(timeFormatter3)){
//                        String startLocalDate = timeFormatter3.toLocalDate() + " " + timeFormatter3.toLocalTime();
//                        if(16==startLocalDate.length()){
//                            startLocalDate=startLocalDate+":00";
//                        }
//                        if(!startLocalDate.contains(".")){
//                            startLocalDate=startLocalDate+".000";
//                        }
//                        TelemetryData res=new TelemetryData();
//                        res.setTime(startLocalDate);
//                        resList.add(res);
//                    }
//                }
//                TelemetryData taskResultVo = taskTrendDataList.get(taskTrendDataList.size() - 1);
//                taskResultVo.setTime(ConvertUtils.formatTime(taskResultVo.getTime()));
//                resList.add(taskResultVo);
//            }else {
//                TelemetryData taskResultVo = taskTrendDataList.get(0);
//                taskResultVo.setTime(ConvertUtils.formatTime(taskResultVo.getTime()));
//                resList.add(taskResultVo);
//            }
//
//        }
//        return resList;
//    }



    /**
     * 补充数据
     *
     * @param xAxis 横坐标
     * @param list  需要补充的数据
     * @return 补充后结果
     */
    public   static List<TaskResultVo> addNullValue(List<String> xAxis, List<TaskResultVo> list) {
        List<TaskResultVo> finalList = new ArrayList<>();
        if (null != list) {
            Map<Object, TaskResultVo> map = new HashMap<>();
            for (TaskResultVo vo : list) {
                map.put(vo.getTime(), vo);
            }
            for (String xa : xAxis) {
                if (map.containsKey(xa)) {
                    finalList.add(map.get(xa));
                } else {
                    TaskResultVo vo=new TaskResultVo();
                    vo.setTime(xa);
                    vo.setValue(null);
                    finalList.add(vo);
                }

            }

        }

        return finalList;
    }
    /**
     * 补充缺失数据
     * @param list 待补充集合
     * @return 补充完的集合
     */
//    public List<TaskResultVo> addDataToList(List<TaskResultVo> taskTrendDataList) {
//        List<TaskResultVo> resList=new ArrayList<>();
//        if (CollUtil.isNotEmpty(taskTrendDataList)) {
//            if(taskTrendDataList.size()>1){
//                for(int i=0;i<taskTrendDataList.size()-1;i++){
//                    TaskResultVo dto=taskTrendDataList.get(i);
//                    TaskResultVo dto2=taskTrendDataList.get(i+1);
//                    String time1 = dto.getTime();
//                    String time2 = dto2.getTime();
//                    time1= ConvertUtils.formatTime(time1);
//                    time2=ConvertUtils.formatTime(time2);
//                    DateTimeFormatter formatter= DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
//                    LocalDateTime timeFormatter1 = LocalDateTime.parse(time1, formatter);
//                    LocalDateTime timeFormatter2 = LocalDateTime.parse(time2, formatter);
//                    LocalDateTime timeFormatter3=timeFormatter1.plus(DiagnoseServiceImpl.AMOUNT_TO_ADD, ChronoUnit.MILLIS);
//                    dto.setTime(time1);
//                    resList.add(dto);
//                    if(timeFormatter2.isAfter(timeFormatter3)){
//                        String startLocalDate = timeFormatter3.toLocalDate() + " " + timeFormatter3.toLocalTime();
//                        if(16==startLocalDate.length()){
//                            startLocalDate=startLocalDate+":00";
//                        }
//                        if(!startLocalDate.contains(".")){
//                            startLocalDate=startLocalDate+".000";
//                        }
//                        TaskResultVo res=new TaskResultVo();
//                        res.setTime(startLocalDate);
//                        resList.add(res);
//                    }
//                }
//                TaskResultVo taskResultVo = taskTrendDataList.get(taskTrendDataList.size() - 1);
//                taskResultVo.setTime(ConvertUtils.formatTime(taskResultVo.getTime()));
//                resList.add(taskResultVo);
//            }else {
//                TaskResultVo taskResultVo = taskTrendDataList.get(0);
//                taskResultVo.setTime(ConvertUtils.formatTime(taskResultVo.getTime()));
//                resList.add(taskResultVo);
//            }
//
//        }
//        return resList;
//    }
    /**
     * 处理时间线中断
     *
     * @param xAxis     完整横坐标
     * @param list      查看子任务横坐标
     * @param trailList 手动试算横坐标
     * @return
     */
    public List<Object> getChangeMap(List<String> xAxis, List<TaskResultVo> list) {
        List<Object> allArrayList = new ArrayList<>();
        if (CollUtil.isNotEmpty(xAxis)) {
            for (String xAxi : xAxis) {
                boolean found = false;
                List<Object> ArrayList = new ArrayList<>();
                if (CollUtil.isNotEmpty(list)) {
                    for (TaskResultVo array : list) {
                        if (array.getTime().equals(xAxi)) {
                            HashMap<String, Object> map = new HashMap<>();
                            map.put("time", xAxi);
                            map.put("value", array.getValue());
                            found = true;
                            allArrayList.add(map);
                            break;
                        }
                    }
                }
                if (!found) {
                    HashMap<String, Object> noMap = new HashMap<>();
                    noMap.put("time", xAxi);
                    noMap.put("value", null);
                    allArrayList.add(noMap);

                }
            }
        } else {
            allArrayList = new ArrayList<>();
        }
        return allArrayList;
    }

    /**
     * 模型
     *
     * @param modelTrain
     * @return
     */
    @SneakyThrows
    private CheckResult<?> calculate(CalculateModelTrain modelTrain) {
        String[] paramCodes =new String[]{modelTrain.getParamCode()};
        TelemetryDto telemetry = new TelemetryDto().setSatelliteCode(modelTrain.getSatelliteCode()).setStartTime(modelTrain.getStartTime()).setEndTime(modelTrain.getEndTime()).setParamCodes(paramCodes);
        Map<String, List<TelemetryData>> listMap = diagnoseService.selectTelemetryData(telemetry);
        //判断是否存在空值
        for (Map.Entry<String, List<TelemetryData>> map : listMap.entrySet()) {
            List<TelemetryData> list = map.getValue();
            if (!CollectionUtils.isEmpty(list)) {
                for (TelemetryData data : list) {
                    if (StringUtils.isEmpty(data.getValue())) {
                        throw new HealthException("参数 " + map.getKey() + " 存在空值.......");
                    }
                }
            }
        }
        HealthAlgorithmManage algorithm = healthAlgorithmManageMapper.selectAlgorithmByName(modelTrain.getAlgorithmName());
        String url = algorithm.getPredictAddr();
        HttpResponse postResponse;
        try {
            postResponse = HttpUtil.createRequest(Method.POST, url).body(JSON.toJSONString(modelTrain)).execute();
        } catch (Exception e) {
            faultReportService.faultReport(ModuleEnum.SHZD.getCode(), ModuleEnum.SHZD.getMsg(),"调用接口失败","调用接口失败");
            return CheckResult.fail("调用接口失败：" + e.getMessage());
        }
        if (postResponse.getStatus() != 200) {
            try {
                Map map = JSONObject.parseObject(postResponse.body(), Map.class);
                log.error("调用模型算法结果异常");
                return CheckResult.fail(map.get("msg").toString());
            } catch (Exception e) {
                faultReportService.faultReport(ModuleEnum.SHZD.getCode(), ModuleEnum.SHZD.getMsg(),"调用算法失败","调用算法异常");
                return CheckResult.fail("调用算法失败，http状态码：" + postResponse.getStatus());
            }
        }
        JSONObject result = JSON.parseObject(postResponse.body());
        if (!result.getInteger("code").equals(200)) {
            return CheckResult.fail(result.getString("msg"));
        }
        Map<String, Object> data = result.getObject("data", Map.class);
        List<Map<String, String>> originalData = (List<Map<String, String>>) data.get("original");
        List<Map<String, String>> calculateResult = (List<Map<String, String>>) data.get("result");
        Map<String, String> map = originalData.get(originalData.size() - 1);
        long startLongTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(map.get("time")).getTime();
        long endTime = startLongTime + ((long) modelTrain.getPredNumber() * modelTrain.getTimeSpan() * 1000);
        TelemetryDto telemetryDto = new TelemetryDto();
        telemetryDto.setSatelliteCode(modelTrain.getSatelliteCode());
        telemetryDto.setParamCode(modelTrain.getParamCode());
        telemetryDto.setParamCodes(new String[]{modelTrain.getParamCode()});
        telemetryDto.setStartTime(new Date(startLongTime));
        telemetryDto.setEndTime(new Date(endTime));
        Map<String, List<TelemetryData>> map1 = diagnoseService.selectTelemetryData(telemetryDto);
        List<TelemetryData> ycListData = map1.get(modelTrain.getParamCode());
        if (CollUtil.isNotEmpty(ycListData)) {
            //ycListData=addTelemetryDataToList(ycListData);
            ycListData=ycListData.stream().sorted(Comparator.comparing(TelemetryData::getTime)).collect(Collectors.toList());
            //originalData=addTelemetryDataToMap(originalData);
            data.put("OriginalForecastCurve", ycListData);
            data.put("original", originalData);
        } else {
            data.put("OriginalForecastCurve", new ArrayList<Map<String, String>>());
        }
        List<String> timeList = getTimeList(originalData, calculateResult, ycListData);
        data.put("xData", timeList);
        data.put("threshold",modelTrain.getThreshold());
        return CheckResult.success(data);
    }
//    /**
//     * 补充缺失数据
//     * @param list 待补充集合
//     * @return 补充完的集合
//     */
//    public List<Map<String, String>> addTelemetryDataToMap(List<Map<String, String>> originalDataList) {
//        List<Map<String, String>> resList=new ArrayList<>();
//        if (CollUtil.isNotEmpty(originalDataList)) {
//            if(originalDataList.size()>1){
//                for(int i=0;i<originalDataList.size()-1;i++){
//                    Map<String, String> dto=originalDataList.get(i);
//                    Map<String, String> dto2=originalDataList.get(i+1);
//                    String time1 = dto.get("time");
//                    String time2 = dto2.get("time");
//                    time1= ConvertUtils.formatTime(time1);
//                    time2=ConvertUtils.formatTime(time2);
//                    DateTimeFormatter formatter= DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
//                    LocalDateTime timeFormatter1 = LocalDateTime.parse(time1, formatter);
//                    LocalDateTime timeFormatter2 = LocalDateTime.parse(time2, formatter);
//                    LocalDateTime timeFormatter3=timeFormatter1.plus(DiagnoseServiceImpl.AMOUNT_TO_ADD, ChronoUnit.MILLIS);
//                    dto.put("time",time1);
//                    resList.add(dto);
//                    if(timeFormatter2.isAfter(timeFormatter3)){
//                        String startLocalDate = timeFormatter3.toLocalDate() + " " + timeFormatter3.toLocalTime();
//                        if(16==startLocalDate.length()){
//                            startLocalDate=startLocalDate+":00";
//                        }
//                        if(!startLocalDate.contains(".")){
//                            startLocalDate=startLocalDate+".000";
//                        }
//                        Map<String, String> map=new HashMap<>();
//                        map.put("time",startLocalDate);
//                        map.put("value",null);
//                        resList.add(map);
//                    }
//                }
//                Map<String, String> stringStringMap = originalDataList.get(originalDataList.size() - 1);
//                stringStringMap.put("time",ConvertUtils.formatTime(stringStringMap.get("time").toString()));
//                stringStringMap.put("value",stringStringMap.get("value"));
//                resList.add(stringStringMap);
//            }else {
//                Map<String, String> stringStringMap = originalDataList.get(0);
//                stringStringMap.put("time",ConvertUtils.formatTime(stringStringMap.get("time").toString()));
//                stringStringMap.put("value",stringStringMap.get("value"));
//                resList.add(stringStringMap);
//            }
//
//        }
//        return resList;
//    }

//    /**
//     * 补充缺失数据
//     * @param list 待补充集合
//     * @return 补充完的集合
//     */
//    public List<TelemetryData> addTelemetryDataToList(List<TelemetryData> taskTrendDataList) {
//        List<TelemetryData> resList=new ArrayList<>();
//        if (CollUtil.isNotEmpty(taskTrendDataList)) {
//            if(taskTrendDataList.size()>1){
//                for(int i=0;i<taskTrendDataList.size()-1;i++){
//                    TelemetryData dto=taskTrendDataList.get(i);
//                    TelemetryData dto2=taskTrendDataList.get(i+1);
//                    String time1 = dto.getTime();
//                    String time2 = dto2.getTime();
//                    time1= ConvertUtils.formatTime(time1);
//                    time2=ConvertUtils.formatTime(time2);
//                    DateTimeFormatter formatter= DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
//                    LocalDateTime timeFormatter1 = LocalDateTime.parse(time1, formatter);
//                    LocalDateTime timeFormatter2 = LocalDateTime.parse(time2, formatter);
//                    LocalDateTime timeFormatter3=timeFormatter1.plus(DiagnoseServiceImpl.AMOUNT_TO_ADD, ChronoUnit.MILLIS);
//                    dto.setTime(time1);
//                    resList.add(dto);
//                    if(timeFormatter2.isAfter(timeFormatter3)){
//                        String startLocalDate = timeFormatter3.toLocalDate() + " " + timeFormatter3.toLocalTime();
//                        if(16==startLocalDate.length()){
//                            startLocalDate=startLocalDate+":00";
//                        }
//                        if(!startLocalDate.contains(".")){
//                            startLocalDate=startLocalDate+".000";
//                        }
//                        TelemetryData res=new TelemetryData();
//                        res.setTime(startLocalDate);
//                        resList.add(res);
//                    }
//                }
//                TelemetryData telemetryData = taskTrendDataList.get(taskTrendDataList.size() - 1);
//                telemetryData.setTime(ConvertUtils.formatTime(telemetryData.getTime()));
//                resList.add(telemetryData);
//            }else {
//                TelemetryData telemetryData = taskTrendDataList.get(0);
//                telemetryData.setTime(ConvertUtils.formatTime(telemetryData.getTime()));
//                resList.add(telemetryData);
//            }
//
//        }
//        return resList;
//    }





    /**
     * 重组预测时间列表
     *
     * @param originalData    原始数据
     * @param calculateResult 预测数据
     * @param ycListData      遥测数据
     * @return
     */
    private List<String> getTimeList(List<Map<String, String>> originalData, List<Map<String, String>> calculateResult,
                                     List<TelemetryData> ycListData) {
        List<String> times = new ArrayList<>();
        originalData.forEach(x -> {
            times.add(x.get("time"));
        });
        ycListData.forEach(x -> {
            times.add(x.getTime());
        });
        calculateResult.forEach(x -> {
            times.add(x.get("time"));
        });

        List<String> stringList = times.stream().distinct().collect(Collectors.toList());
        stringList = stringList.stream().sorted().collect(Collectors.toList());
        return stringList;
    }

    /**
     * 组装模型参数列表数据
     *
     * @param modelTrain
     * @return
     */
    public List<ModelAlgorithmInfo> assembleAlgorithmParamList(CalculateModelTrain modelTrain, Long recordId, List<AlgorithmParams> algorithmParamList) {
        algorithmParamList.sort(Comparator.comparing(AlgorithmParams::getId));
        CalculateUpdateModelParam calculateUpdateModelParam = new CalculateUpdateModelParam();
        calculateUpdateModelParam.setFilters(algorithmParamList.get(0).getParamValueEnd());
        calculateUpdateModelParam.setActivation(algorithmParamList.get(1).getParamValueEnd());
        calculateUpdateModelParam.setUnits(algorithmParamList.get(2).getParamValueEnd());
        calculateUpdateModelParam.setLstmActivation(algorithmParamList.get(3).getParamValueEnd());
        calculateUpdateModelParam.setDenseActivation(algorithmParamList.get(4).getParamValueEnd());
        calculateUpdateModelParam.setLossMetric(algorithmParamList.get(5).getParamValueEnd());
        calculateUpdateModelParam.setOptimizer(algorithmParamList.get(6).getParamValueEnd());
        calculateUpdateModelParam.setEpochs(algorithmParamList.get(7).getParamValueEnd());
        calculateUpdateModelParam.setBatchSize(algorithmParamList.get(8).getParamValueEnd());
        modelTrain.setCalculateUpdateModelParam(calculateUpdateModelParam);
        List<ModelAlgorithmInfo> modelAlgorithmInfos = new ArrayList<>(algorithmParamList.size());
        algorithmParamList.forEach(x -> {
            ModelAlgorithmInfo modelAlgorithmInfo = cn.kawins.base.utils.BeanUtil.copyBean(x, ModelAlgorithmInfo.class);
            modelAlgorithmInfo.setModelId(recordId.toString());
            if (StrUtil.isNotEmpty(modelTrain.getOldModelName()))
                modelAlgorithmInfo.setModelId(modelTrain.getOldModelName());
            modelAlgorithmInfo.setId(null);
            modelAlgorithmInfos.add(modelAlgorithmInfo);
        });
        return modelAlgorithmInfos;
    }


}
